package Image;

import Common.MathUtils;
import Training.TrainingData;
import imageannotation.ImageAnnotationApp;
import java.util.Vector;
import org.jdesktop.application.Application;
import org.jdesktop.application.Task;
import Image.segment.Segment;

/**
 * Runs the Annotation task in a worker thread
 * 
 * @author Seth Wessitsh <seth@wessitsh.com>
 */
public class Annotater extends Task<SegmentedImage,Void> {
	private SegmentedImage imageToAnnotate = null;
	private TrainingData trainingData = null;
	private ImageAnnotationApp application;

	public Annotater(
		Application app,
		TrainingData data,
		SegmentedImage imageToAnnotate
	) {
		super(app);
		application = (ImageAnnotationApp) app;
		this.trainingData = data;
		this.imageToAnnotate = imageToAnnotate;
	}

	/**
	 * Called to run the annotation automatically after {@link #execute()} is called on
	 * the instance.
	 *
	 * @return the image which was annotated
	 * @throws java.lang.Exception
	 */
	@Override
	protected SegmentedImage doInBackground() throws Exception {
		annotateImage();

		return imageToAnnotate;
	}

	/**
	 * Calls the application with the SegmentedImage after annotation is finished
	 * 
	 * @param arg0 The SegmentedImage which was annotated
	 */
	@Override
	protected void succeeded(SegmentedImage arg0) {
		((ImageAnnotationApp)getApplication()).annotationFinished(arg0);
	}

	/**
	 * Compares each unknown segment in the image to annotate to each mean segment using
	 * the {@link Segment#getSimilarity(Image.segment.Segment)} method of the mean
	 * segment instance.  If the similarity value returned is less than the threshold
	 * for the word associated with the mean segment and less than the current
	 * similarity we use that similarity value and use this word as the word for the
	 * segment.
	 */
	private void annotateImage() {
		String currentWord = "?"; // "word" for segments which cannot be annotated
		double similarity = 0.2; // arbitrary maximum distance to be considered similar
		Vector<String> newAnnotationVector = new Vector<String>();
		boolean useCV = application.useCVScores();

		for (Segment unkSeg : imageToAnnotate.getSegments()) {
			for (String potentialWord : trainingData.getWords()) {
				double threshold = MathUtils.mag(
					trainingData.getWordThresholds(potentialWord)
				);
				double temp = trainingData
					.getSegment(potentialWord)
					.getSimilarity(unkSeg, useCV);

//				System.out.println("Threshold (" + potentialWord + "): " + threshold);
//				System.out.println("Similarity (" + potentialWord + "): " + temp);

				if (application.useThresholds()) {
					if (temp < threshold && temp < similarity) {
						currentWord = potentialWord;
						similarity = temp;
					}
				} else {
					if (temp < similarity) {
						currentWord = potentialWord;
						similarity = temp;
					}
				}
			}

			newAnnotationVector.add(currentWord);
			similarity = 0.2; // reset values
		}
		imageToAnnotate.setWords(newAnnotationVector); // assign the words to the image
	}
}
